from django.http import HttpResponse
from django.shortcuts import render
from django.db.models import F, Q
from .models import BookInfo, PeopleInfo
from django.db.models import Sum
from django.urls import reverse
import json
from django.http import JsonResponse



def book_test(request):
    return HttpResponse('OK!')

"""
路由反转（reverse）
（1）url(r'^',include('book.urls',name='book'))
（2）url(r'^testproject/$',views.testproject,name='test')

带参数的反转
"""
def reverse_test(request):

    url = reverse('book_app:test')
    print(url)
    return HttpResponse('index')

"""
HTTP协议向服务器传参有几种途径？
(1)提取URL的特定部分([path 函数 /re_path()函数[位置参数+关键字参数])，如/weather/beijing/2018，可以在服务器端的路由中用正则表达式截取；
（2）查询字符串（query string)，形如key1=value1&key2=value2；
(3)请求体（body）中发送的数据，比如表单数据、json、xml；
在http报文的头（header）中。

"""
#（1）提取URL的特定部分-位置参数   http://127.0.0.1:8000/booklist/18/188/
def positional_argument(request, value1, value2):
    # 构造上下文
    context = {'v1': value1, 'v2': value2}
    url = reverse('book_app:positional_argument', args=[value1, value2]) # 带参数的反转
    print(url)
    return render(request, 'Book/index.html', context)


# (3)由前端发来的数据-请求体：http://127.0.0.1:8000/booklist/
def body_argument(request):
    return render(request, 'Book/index2.html')

def receive_data(request):
    if request.method == 'POST':
        try:
            data = json.loads(request.body.decode('utf-8'))
            print("接收到的数据:", data)
            response_data = {
                "message": "数据已成功接收",
                "received_data": data
            }
            return JsonResponse(response_data)
        except json.JSONDecodeError:
            return JsonResponse({"error": "请求体不是有效的 JSON 格式"}, status=400)
        except Exception as e:
            return JsonResponse({"error": str(e)}, status=500)
    return JsonResponse({"error": "只支持 POST 请求"}, status=405)

#（2）提取URL的查询字符串 http://127.0.0.1:8000/booklist/query?name="巫明瑾"&gender="女"
def query_argument(request):
    value1 = request.GET.get('name')
    value2 = request.GET.get('gender')

    context = {
        'v1': value1,
        'v2': value2
    }

    return render(request,'Book/index.html',context)

"""
响应 HttpResponse

"""
def simple_reaponse(request):
    context = {'message': '这是从视图传递到模板的数据'}
    return  render(request, 'Book/index3.html', context)






"""
1.数据库操作-新增数据:2种 save() / 模型类.objects.create()
外键关联表保存数据：3种
"""

def add_view(request):
    book = BookInfo(
        name ="新增书籍1",
        pub_date='2025-4-29')
    book.save()

# 1.创建关联对象时显式指定外键实例(最常用！)
    PeopleInfo.objects.create(
        name='巫明瑾',
        book=book  )
    # 等号左边的 book 是 PeopleInfo 模型里的外键字段名；等号右边的 book 是前面创建并保存到数据库的 BookInfo 模型实例
    # 当执行 PeopleInfo.objects.create() 方法时，Django 会把 BookInfo 实例 book 的主键值（通常是 id 字段）存储到 PeopleInfo 表的 book 字段中，以此来建立人物和书籍之间的关联


# 2. 创建关联对象时指定外键的主键值
    # book_id = book.id # 获取 BookInfo 实例的主键值
    # PeopleInfo.objects.create(name='巫明瑾', book=book_id) # 创建 PeopleInfo 实例并通过主键值关联 BookInfo 实例

# 3.先创建对象，再设置外键关联
#     people = PeopleInfo(name='巫明瑾')
#     people.save() # 创建 PeopleInfo 实例，但不立即关联 BookInfo 实例
#     people.book = book
#     people.save()

    return HttpResponse("新增书籍1,作者巫明瑾创建成功！！")

"""
2.数据库操作-修改数据:2种 save() / 模型类.objects.filter().update()
"""
def update_view(request):
    BookInfo.objects.filter(name="新增书籍1").update(name="修改书籍2")

    person = PeopleInfo.objects.get(name="巫明瑾")
    person.name = "更改巫明瑾"
    person.save()

    return HttpResponse("更改数据成功！！")

"""
3.数据库操作-删除数据:2种 模型类对象delete / 模型类.objects.filter().delete()
"""
def delete_view(request):
    person = PeopleInfo.objects.get(name="更改巫明瑾")
    person.delete()

    BookInfo.objects.filter(name="修改书籍2").delete()
    return HttpResponse("删除成功！！！")


"""
4.查询
a.基础查询
（1）get 获取单一结果，没有结果就会抛异常（模型类.DoesNotExist）
（2）all查询多个结果
（3）count查询结果数量
b.过滤查询 类似where (属性名称__比较运算符=值)
# 属性名称和比较运算符间使用两个下划线，所以属性名不能包括多个下划线
# 比较运算符：iexact、icontains、istartswith、iendswith （i表示不区分大小写）、isnull、in(范围查询)
# 比较查询（>gt >=gte lt< lte<=）
# 日期查询（year、month、day、week_day、hour、minute、second）
（1）get 单一结果
（2）filter 过滤多个结果
（3）exclude 排除掉符合条件的，取剩余结果
c.F / Q对象
（1）F 两个属性进行比较 F(属性名)
（2）Q 实现或or查询,使用&、|连接，&表示逻辑与，|表示逻辑或 Q(属性名__运算符=值)
d.聚合函数 和 排序函数
(1)aggregate()过滤器调用聚合函数 [Avg平均，Count数量，Max最大，Min最小，Sum求和]
e.关联查询（多表查询）
（1）1对多查询： 一对应的模型类对象.多对应的模型类名小写_set；

"""
"""
查询结果集：<class 'django.db.models.query.QuerySet'>

    all()：返回所有数据。
    filter()：返回满足条件的数据。
    exclude()：返回满足条件之外的数据。
    order_by()：对结果进行排序。

book 就是 BookInfo 类的一个实例：<class 'book.models.BookInfo'>


惰性执行；
缓存；
"""
def foundation_query(request):
    book = BookInfo.objects.get(id=1) # 返回定义的 BookInfo 模型类的实例
    books = BookInfo.objects.all()  # 当执行如下语句时，并未进行数据库查询，只是创建了一个查询集books;返回一个包含所有 Book 模型实例的查询集
    book_count = BookInfo.objects.count()

    # for book in books: # 继续执行遍历迭代操作后，才真正的进行了数据库的查询
    #     print(book.name)

    print(book, type(book))
    print(books,type(books))
    print(book_count, type(book_count))
    return HttpResponse(f"id=1的书是{book}/{books}/{book_count}")

def filter_query(request):
    book = BookInfo.objects.filter(id=1) #查询编号为1的图书
    book2 = BookInfo.objects.filter(name__contains='传') #查询书名包含'传'的图书
    book3 = BookInfo.objects.filter(name__endswith='1') #查询书名以'部'结尾的图书
    book4 = BookInfo.objects.filter(name__startswith='雪')#查询书名以'雪'开头的图书
    book5 = BookInfo.objects.filter(name__isnull=True) # 查询书名为空的图书 ==>不存在这样的数据
    book6 = BookInfo.objects.filter(id__in=[1,2,3]) # 查询编号为1或2或3的图书
    book7 = BookInfo.objects.filter(id__gt=3) # 查询编号大于3的图书
    book8 = BookInfo.objects.exclude(id=3) # 查询编号不等于3的图书
    book9 = BookInfo.objects.filter(pub_date__year=1980) #查询1980年发表的图书
    book10 = BookInfo.objects.filter(pub_date__gt='1990-1-1') # 查询1990年1月1日后发表的图书。

    print(book,type(book)) # <QuerySet [<BookInfo: 射雕英雄传>]>
    print(book2,type(book2)) # <QuerySet [<BookInfo: 射雕英雄传>]>
    print(book3, type(book3)) # <QuerySet [<BookInfo: 新增书籍1>, <BookInfo: 新增书籍1>]>
    print(book4, type(book4)) # <QuerySet [<BookInfo: 雪山飞狐>]>
    print(book5, type(book5)) #<QuerySet []>
    print(book6, type(book6))  # <QuerySet [<BookInfo: 射雕英雄传>, <BookInfo: 天龙八部>, <BookInfo: 笑傲江湖>]>
    print(book7, type(book7))  # <QuerySet [<BookInfo: 雪山飞狐>, <BookInfo: 新增书籍1>, <BookInfo: 新增书籍1>]>
    print(book8, type(book8)) #<QuerySet [<BookInfo: 射雕英雄传>, <BookInfo: 天龙八部>, <BookInfo: 雪山飞狐>, <BookInfo: 新增书籍1>, <BookInfo: 新增书籍1>]>
    print(book9, type(book9)) # <QuerySet [<BookInfo: 射雕英雄传>]>
    print(book10, type(book10)) # <QuerySet [<BookInfo: 笑傲江湖>, <BookInfo: 新增书籍1>, <BookInfo: 新增书籍1>]>

    return HttpResponse("过滤查询成功")

def FQ_query(request):
    book1 = BookInfo.objects.filter(readcount__gte=F('commentcount')) # 查询阅读量大于等于评论量的图书
    book2 = BookInfo.objects.filter(readcount__gt=F('commentcount')*2) #询阅读量大于2倍评论量的图书
    book3 = BookInfo.objects.filter(readcount__gt=20, id__lt=3) # 查询阅读量大于20，并且编号小于3的图书
    book4 = BookInfo.objects.filter(readcount__gt=20).filter(id__lt=3) # 同上
    book5 = BookInfo.objects.filter(Q(readcount__gt=20)) # 查询阅读量大于20
    book6 = BookInfo.objects.filter(Q(readcount__gt=20) | Q(id__lt=3)) # 查询阅读量大于20，或编号小于3的图书，只能使用Q对象实现
    book7 = BookInfo.objects.filter(~Q(id=3)) # 查询编号不等于3的图书



    print(book1, type(book1))
    print(book2, type(book2))
    print(book3, type(book3))
    print(book4, type(book4))
    print(book5, type(book5))
    print(book6, type(book6))
    print(book7, type(book7))


    return HttpResponse("FQ对象查询成功！！")

def agg_order(request):
    book1 = BookInfo.objects.aggregate(Sum('readcount')) #查询图书的总阅读量
    book2 = BookInfo.objects.count()    # 查询图书总数,count直接使用
    book3 = BookInfo.objects.all().order_by('readcount') # 默认升序
    book4 = BookInfo.objects.all().order_by('-readcount')
    books5 = BookInfo.objects.filter(readcount__gt=30).order_by('pub_date')

    print(book1,type(book1))  #{'readcount__sum': 126} {'属性名__聚合类小写':值}
    print(book2, type(book2))   # int
    print(book3, type(book3))
    print(book4, type(book4))

    return HttpResponse("聚合函数 和 排序函数！！！")

def relate_query(request):
    # 查询书籍为1的所有人物信息 （1对多）
    book = BookInfo.objects.get(id=1)
    persons = book.peopleinfo_set.all()

    # 查询人物为1的书籍信息(多对应的模型类对象.多对应的模型类中的关系类属性名 )
    person = PeopleInfo.objects.get(name="黄蓉")
    book = person.book
    # 多对应的模型类对象.关联类属性_id
    person1 = PeopleInfo.objects.get(name="黄蓉")
    book2 = person1.book_id

    book3 = BookInfo.objects.filter(peopleinfo__name='郭靖') #查询图书，要求图书人物为"郭靖"
    book4 = BookInfo.objects.filter(peopleinfo__description__contains='八') #查询图书，要求图书中人物的描述包含"八"
    people2 = PeopleInfo.objects.filter(book__name='天龙八部') # 查询书名为“天龙八部”的所有人物
    people3 = PeopleInfo.objects.filter(book__readcount__gt=30)  # 查询图书阅读量大于30的所有人物

    print(persons,type(persons))
    print(book4, type(book4))

    return HttpResponse("关联查询成功！！！")



